package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author waker
 * @since 2025-10-25
 */
@Service
@RequiredArgsConstructor
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {

    @Autowired
    private IInteractionQuestionService questionService;
    private final InteractionReplyMapper replyMapper;
    private final UserClient userClient;

    /**
     * 9. 新增回答或评论(用户-管理端共用)
     *
     * @param replyDTO
     */
    @Override
    @Transactional
    public void saveReplyOrComment(ReplyDTO replyDTO) {
        // 1. 内容审核 TODO

        // 2. 新增
        InteractionReply interactionReply = BeanUtils.copyBean(replyDTO, InteractionReply.class);
        interactionReply.setUserId(UserContext.getUser());
        boolean result = this.save(interactionReply);
        if (!result) {
            throw new RuntimeException("新增失败");
        }

        // 3. 判断是回答还是评论 是回答: 回答id为空 且 回复目标ID为空
        Long questionId = replyDTO.getQuestionId();
        Long answerId = replyDTO.getAnswerId();
        Long targetReplyId = replyDTO.getTargetReplyId();

        // 3.1 更新问题表：最近一次回答ID 、回答数量 +1
        if (ObjectUtil.isAllEmpty(answerId, targetReplyId)) {
            // 3.2 判断是否是学生回答 是：更新查看状态为 未查看
            questionService.lambdaUpdate()
                    .set(InteractionQuestion::getLatestAnswerId, interactionReply.getId())
                    .set(replyDTO.getIsStudent(), InteractionQuestion::getStatus, 0)
                    .setSql("answer_times = answer_times + 1")
                    .eq(InteractionQuestion::getId, questionId)
                    .update();
        }

        // 4. 是评论
        // 4.1 更新回复表：回答的评论数量 +1
        this.lambdaUpdate()
                .setSql("reply_times = reply_times + 1")
                .eq(InteractionReply::getId, interactionReply.getId())
                .update();
    }

    /**
     * 10. 分页查询回答或评论列表(用户-管理端共用)
     *
     * @param query
     * @param isStudent
     * @return
     */
    @Override
    public PageDTO<ReplyVO> pageQuery(ReplyPageQuery query, Boolean isStudent) {
        // 1. 参数校验
        Long questionId = query.getQuestionId();
        Long answerId = query.getAnswerId();
        if (ObjectUtil.isEmpty(questionId) && ObjectUtil.isEmpty(answerId)) {
            throw new BadRequestException("问题ID和回答ID不能同时为空！");
        }

        // 2. 判断是查询回答列表还是查询评论列表
        // 2.1 查询回答列表
        Page<InteractionReply> pageResult = new Page<>();
        if (ObjectUtil.isEmpty(answerId) && ObjectUtil.isNotEmpty(questionId)) {
            // 2.1.1 发起回答分页查询
            // select * from interaction_reply where question_id = ? and answer_id is 0
            // order by like_times desc, create_time desc limit ?,?
            pageResult = this.lambdaQuery()
                    .eq(InteractionReply::getQuestionId, questionId)
                    .eq(InteractionReply::getAnswerId, 0)
                    // 如果是学生查询，过滤掉已隐藏的
                    .eq(isStudent, InteractionReply::getHidden, false)
                    .page(query.toMpPage(new OrderItem("liked_times", false), new OrderItem("create_time", false)));
            List<InteractionReply> records = pageResult.getRecords();
            if (ObjectUtil.isEmpty(records)) {
                return PageDTO.empty(0L, 0L);
            }
            // 2.1.2 收集问题回答者ID,转为IdSet集合 /还有回答ID的集合，用于统计（未隐藏）评论数量
            Set<Long> userIds = new HashSet<>(records.size());
            Set<Long> answerIds = new HashSet<>(records.size());
            for (InteractionReply record : records) {
                userIds.add(record.getUserId());
                answerIds.add(record.getId());
            }
            // 2.1.3 查询用户信息,转为map集合(Map -> 用户ID:用户对象)
            Map<Long, UserDTO> userInfoMap = queryUserInfoAnd2Map(userIds);

            // 3 判断是学生查询还是管理端查询 学生查询（只显示回答下未隐藏的评论/匿名用户不展示信息）
            List<ReplyVO> voList = new ArrayList<>();
            voList = isStudent ? studentAnswerPageQuery(answerIds, records, userInfoMap) : managerAnswerPageQuery(records, userInfoMap);
            // 4. 封装并返回结果
            return PageDTO.of(pageResult, voList);
        }

        // 2.2 查询评论列表
        // 2.2.1 发起分页查询
        pageResult = this.lambdaQuery()
                .eq(InteractionReply::getAnswerId, answerId)
                // 如果是学生查询，过滤掉已隐藏的
                .eq(isStudent, InteractionReply::getHidden, false)
                .page(query.toMpPage(new OrderItem("liked_times", false), new OrderItem("create_time", false)));
        List<InteractionReply> records = pageResult.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return PageDTO.empty(0L, 0L);
        }

        // 2.2.2 收集问题回答者ID和目标用户ID，转为IdSet集合
        Set<Long> userIds = new HashSet<>(records.size());
        // 收集目标回复id  用于判断评论目标用户是否匿名，非匿名，设置用户昵称
        Set<Long> targetReplyIds = new HashSet<>(records.size());
        for (InteractionReply record : records) {
            userIds.add(record.getUserId());
            userIds.add(record.getTargetUserId());
            targetReplyIds.add(record.getTargetReplyId());
        }

        // 2.2.3 查询用户信息,转为map集合(Map -> 用户ID:用户对象)
        Map<Long, UserDTO> userInfoMap = queryUserInfoAnd2Map(userIds);

        // 2.2.4 获取目标回复信息，转为map集合(Map -> 目标回复ID:是否匿名)
        Map<Long, Boolean> targetIsAnonymityMap = this.lambdaQuery()
                .in(InteractionReply::getId, targetReplyIds)
                .select(InteractionReply::getId, InteractionReply::getAnonymity)
                .list().stream().collect(Collectors.toMap(InteractionReply::getId, InteractionReply::getAnonymity));

        List<ReplyVO> voList = commentPageQuery(isStudent, records, userInfoMap, targetIsAnonymityMap);

        // 4. 封装并返回结果
        return PageDTO.of(pageResult, voList);
    }

    /**
     * 评论列表分页查询
     * @param isStudent
     * @param records
     * @param userInfoMap
     * @param targetIsAnonymityMap
     * @return
     */
    private static List<ReplyVO> commentPageQuery(Boolean isStudent, List<InteractionReply> records, Map<Long, UserDTO> userInfoMap, Map<Long, Boolean> targetIsAnonymityMap) {
        // 3. 循环遍历当前页码分页数据，封装vo集合
        List<ReplyVO> voList = new ArrayList<>();
        for (InteractionReply record : records) {
            // 3.1 属性拷贝
            ReplyVO replyVO = BeanUtils.copyBean(record, ReplyVO.class);
            // 3.2 补全用户信息 判断是学生查询还是管理端查询 学生查询（匿名用户不展示信息）
            UserDTO userInfo = userInfoMap.get(record.getUserId());
            if (isStudent) {
                if (!record.getAnonymity()) {
                    if (ObjectUtil.isNotEmpty(userInfo)) {
                        replyVO.setUserName(userInfo.getName());
                        replyVO.setUserIcon(userInfo.getIcon());
                    }
                }
            } else {
                if (ObjectUtil.isNotEmpty(userInfo)) {
                    replyVO.setUserName(userInfo.getName());
                    replyVO.setUserIcon(userInfo.getIcon());
                }
            }
            // 2.3 补全点赞信息 TODO
            // 2.4 补全目标用户信息
            // 判断是学生查询还是管理端查询 学生查询:评论目标用户非匿名，设置用户昵称
            if (!isStudent) {
                replyVO.setTargetUserName(userInfoMap.get(record.getTargetUserId()).getName());
            } else {
                if (ObjectUtil.isNotEmpty(targetIsAnonymityMap)){
                    Boolean isAnonymity = targetIsAnonymityMap.get(record.getTargetReplyId());
                    if (ObjectUtil.isNotNull(isAnonymity)){
                        if (!isAnonymity) {
                            replyVO.setTargetUserName(userInfoMap.get(record.getTargetUserId()).getName());
                        }
                    }
                }
            }

            // 2.4 添加到vo集合
            voList.add(replyVO);
        }
        return voList;
    }


    /**
     * 管理端回答分页查询
     *
     * @param records
     * @param userInfoMap
     * @return
     */
    private List<ReplyVO> managerAnswerPageQuery(List<InteractionReply> records, Map<Long, UserDTO> userInfoMap) {
        // 1. 管理端访问某问题的回答后，修改问题状态为 已查看
        questionService.lambdaUpdate()
                .set(InteractionQuestion::getStatus, 1)
                .eq(InteractionQuestion::getId, records.get(0).getQuestionId())
                .update();
        // 2. 循环遍历当前页码分页数据，封装vo集合
        List<ReplyVO> voList = new ArrayList<>();
        for (InteractionReply record : records) {
            // 2.1 属性拷贝
            ReplyVO replyVO = BeanUtils.copyBean(record, ReplyVO.class);
            // 2.2 补全用户信息
            UserDTO userInfo = userInfoMap.get(record.getUserId());
            if (ObjectUtil.isNotEmpty(userInfo)) {
                replyVO.setUserName(userInfo.getName());
                replyVO.setUserIcon(userInfo.getIcon());
            }
            // 2.3 补全点赞信息 TODO
            // 2.4 添加到vo集合
            voList.add(replyVO);
        }
        // 3. 返回
        return voList;
    }

    /**
     * 用户端回答分页查询
     *
     * @param answerIds
     * @param records
     * @param userInfoMap
     * @return
     */
    private List<ReplyVO> studentAnswerPageQuery(Set<Long> answerIds, List<InteractionReply> records, Map<Long, UserDTO> userInfoMap) {
        // 1 统计未隐藏的评论数量,转为Map(Map -> 回答ID:未隐藏的评论数量)
        QueryWrapper<InteractionReply> replyQueryWrapper = new QueryWrapper<>();
        replyQueryWrapper.select("answer_id,count(1) num")
                .eq("hidden", false)
                .in("answer_id", answerIds)
                .groupBy("answer_id");
        List<Map<String, Object>> unHideCommentCountListMap = replyMapper.selectMaps(replyQueryWrapper);
        Map<Long, Integer> unHideCommentCountMap = new HashMap<>(unHideCommentCountListMap.size());
        if (ObjectUtil.isNotEmpty(unHideCommentCountListMap)) {
            unHideCommentCountMap = unHideCommentCountListMap.stream().collect(Collectors.toMap(
                    map -> Long.parseLong(map.get("answer_id").toString()),
                    map -> Integer.parseInt(map.get("num").toString())));
        }
        // 2. 循环遍历当前页码分页数据，封装vo集合
        List<ReplyVO> voList = new ArrayList<>();
        for (InteractionReply record : records) {
            // 2.1 属性拷贝
            ReplyVO replyVO = BeanUtils.copyBean(record, ReplyVO.class);
            // 2.2 补全用户信息
            if (!record.getAnonymity()) {
                UserDTO userInfo = userInfoMap.get(record.getUserId());
                if (ObjectUtil.isNotEmpty(userInfo)) {
                    replyVO.setUserName(userInfo.getName());
                    replyVO.setUserIcon(userInfo.getIcon());
                }
            }
            // 2.3 补全点赞信息 TODO
            // 2.4 补全未隐藏评论数量
            replyVO.setReplyTimes(unHideCommentCountMap.getOrDefault(record.getId(), 0));
            // 2.5 添加到vo集合
            voList.add(replyVO);
        }
        // 3 返回
        return voList;
    }

    /**
     * 查询用户信息并转为Map集合
     *
     * @param userIds
     * @return
     */
    private Map<Long, UserDTO> queryUserInfoAnd2Map(Set<Long> userIds) {
        List<UserDTO> userDTOList = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userInfoMap = new HashMap<>(userDTOList.size());
        if (ObjectUtil.isNotEmpty(userDTOList)) {
            userInfoMap = CollStreamUtil.toIdentityMap(userDTOList, UserDTO::getId);
        }
        return userInfoMap;
    }
}
